#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "math.h"
#include "assert.h"

#include "conio.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"
#include "Ufeatureterm.h"
#include "AUfeatureterm.h"
#include "FT_refinement.h"
#include "FT_generalization.h"

#include "Plan.h"


// #define DEBUG_MESSAGES
#define MAX_SIMULTANEOUS_PLANS	1
	


void tree_planner(FTKBase *domain_model, Ontology *o)
{
	List<FeatureTerm> *actions=0;
	Plan *plan,*final_plan=0;
	FeatureTerm *selected_operator;		// unsatisfied operator
	FeatureTerm *selected_condition;	// unsatisfied condition
	FeatureTerm *selected_operator2;	// operator that will satisfy the unsatisfied condition
	List<Plan> open_plans;
	int iteration=0;

	{
		FeatureTerm *pattern=FeatureTerm::fromStringNOOS("(define (plotpoint))",domain_model,o);
		actions=domain_model->RetrieveFT(pattern);
		delete pattern;
	}

	printf("%i Basic actions to construct plotpoints\n",actions->Length());

	// Seed the algorithm:
	plan=new Plan();
	plan->m_operators.Add(FeatureTerm::fromStringNOOS("(define (plotpoint) (name \"endgame\") (preconditions (define (endgame))))",domain_model,o));
	open_plans.Add(plan);

	while(!open_plans.EmptyP() && final_plan==0) {
		printf("- Iteration %i -------------------------------------------------------------\n",iteration++);

#ifdef MAX_SIMULTANEOUS_PLANS
		while(open_plans.Length()>MAX_SIMULTANEOUS_PLANS) delete open_plans.ExtractRandom();
#endif

		printf("open plans: %i\n\n",open_plans.Length());

		selected_operator=0;
		selected_condition=0;
		selected_operator2=0;
	
		// plan=open_plans.ExtractIni();
		plan=open_plans.ExtractRandom();
		// plan=open_plans.Extract();

#ifdef DEBUG_MESSAGES
		{
			
			char *s;
			printf("Plan selected to expand:\n");
			s=plan->toStringNOOS(domain_model);
			printf("%s\n",s);
			delete []s;
			plan->print_orderings();
			printf("\n");

			printf("Human readable form:\n");
			plan->human_readable_print(domain_model);
			printf("\n");
		}
#endif

		// Iterate through the unsatisfied preconditions:
		{
			List<FeatureTerm> *l1=0;

			selected_operator=0;
			selected_condition=0;

			l1=plan->get_unsatisfied_operators();
#ifdef DEBUG_MESSAGES
			printf("%i unsatisfied operators\n",l1->Length());
#endif
			while(!l1->EmptyP()) {
				selected_operator=l1->ExtractIni();

#ifdef DEBUG_MESSAGES
				{
					char *s;
					printf("Selected Operator is:\n");
					s=selected_operator->toStringNOOS(domain_model);
					printf("%s\n\n",s);
					delete []s;
				}
#endif

				List<FeatureTerm> *l2=plan->get_unsatisfied_preconditions(selected_operator);
#ifdef DEBUG_MESSAGES
				printf("%i unsatisfied conditions in selected operator\n\n",l2->Length());
#endif
				while(!l2->EmptyP()) {
					selected_condition=l2->ExtractIni();

#ifdef DEBUG_MESSAGES
					{
						char *s;
						printf("Selected Condition is:\n");
						s=selected_condition->toStringNOOS(domain_model);
						printf("%s\n",s);
						delete []s;
						printf("\n");
					}	
#endif

					{
						List<FeatureTerm> *l3;
						FeatureTerm *conditions,*condition2,*op,*tmp;
						List<FeatureTerm> conditions_l;
						bool candidate;
						int n_existing=0,n_new=0;

						l3=plan->get_operators_to_satisfy(selected_condition,o,domain_model);
						n_existing=l3->Length();
						
						actions->Rewind();
						while(actions->Iterate(op)) {
							conditions=op->featureValueQuick("postconditions");
							if (conditions!=0) {
								if (conditions->isFeatureTerm()) {
									conditions_l.Add(conditions);
								} else {
									List<FeatureTerm> *ltmp=conditions->set_values_quick();
									ltmp->Rewind();
									while(ltmp->Iterate(condition2)) conditions_l.Add(condition2);
								} // if 
							} // if

							candidate=false;
							while(!conditions_l.EmptyP() && !candidate) {
								condition2=conditions_l.ExtractIni();
								
								tmp = simple_unification(selected_condition,condition2,o,domain_model);
								if (tmp!=0) {
									delete tmp;
									candidate=true;
								} // if 
							} // while 

							if (candidate) {
								l3->Add(op);
								n_new++;
							} // if 
						} // while 

#ifdef DEBUG_MESSAGES
						printf("%i existing operators can satisfy the precondition\n",n_existing);
						printf("%i new operators can satisfy the precondition\n\n",n_new);
#endif

						selected_operator2=0;

						while(!l3->EmptyP()) {
							selected_operator2=l3->ExtractIni();
#ifdef DEBUG_MESSAGES
							{
								char *s;
								printf("Selected Operator to satisfy the condition is:\n");
								s=selected_operator2->toStringNOOS(domain_model);
								printf("%s\n\n",s);
								delete []s;
							}
#endif

							// Clone plan:
							{
								List<FeatureTerm> old_nodes,new_nodes;
								int pos;
								FeatureTerm *new_selected_operator=0;
								FeatureTerm *new_selected_condition=0;
								FeatureTerm *new_selected_operator2=0;

								Plan *new_plan=plan->clone(domain_model,&old_nodes,&new_nodes);

								pos=old_nodes.Position(selected_operator);
								assert(pos!=-1);
								new_selected_operator=new_nodes[pos];

								pos=old_nodes.Position(selected_condition);
								assert(pos!=-1);
								new_selected_condition=new_nodes[pos];

								pos=old_nodes.Position(selected_operator2);
								if (pos==-1) {
									assert(actions->MemberP(selected_operator2));
									new_selected_operator2=selected_operator2;
								} else {
									new_selected_operator2=new_nodes[pos];
								} // if 

								// Add the new operator:
								if (actions->MemberP(new_selected_operator2)) {
									new_selected_operator2=new_selected_operator2->clone();
									new_plan->m_operators.Add(new_selected_operator2);
								} // if 

								// Unify conditions:
								{
									FeatureTerm *conditions;
									List<FeatureTerm> conditions_l;
									List<UnificationResult> *l=0;
									UnificationResult *r=0;

									conditions=new_selected_operator2->featureValueQuick("postconditions");
									if (conditions!=0) {
										if (conditions->isFeatureTerm()) {
											conditions_l.Add(conditions);
										} else {
											List<FeatureTerm> *ltmp=conditions->set_values_quick();
											ltmp->Rewind();
											while(ltmp->Iterate(condition2)) conditions_l.Add(condition2);
										} // if 
									} // if

									r=0;
									while(!conditions_l.EmptyP() && r==0) {
										condition2=conditions_l.ExtractIni();
										
										l = unification_with_bindings(new_selected_condition,condition2,o,domain_model);
										if (l!=0) r=l->ExtractIni();					
									} // while 

									assert(r!=0);

									// Perform all the substitutions:
									{
										UnificationBinding *b;
										FeatureTerm *f;

										r->m_bindings.Rewind();
										while(r->m_bindings.Iterate(b)) {
											new_plan->m_operators.Rewind();
											while(new_plan->m_operators.Iterate(f)) {
												if (b->m_f1!=0) f->substitute(b->m_f1,b->m_u);
												if (b->m_f2!=0) f->substitute(b->m_f2,b->m_u);
											} // while 
											new_plan->m_precedence_before.Rewind();
											while(new_plan->m_precedence_before.Iterate(f)) {
												if (b->m_f1!=0) f->substitute(b->m_f1,b->m_u);
												if (b->m_f2!=0) f->substitute(b->m_f2,b->m_u);
											} // while 
											new_plan->m_precedence_condition.Rewind();
											while(new_plan->m_precedence_condition.Iterate(f)) {
												if (b->m_f1!=0) f->substitute(b->m_f1,b->m_u);
												if (b->m_f2!=0) f->substitute(b->m_f2,b->m_u);
											} // while 
											new_plan->m_precedence_after.Rewind();
											while(new_plan->m_precedence_after.Iterate(f)) {
												if (b->m_f1!=0) f->substitute(b->m_f1,b->m_u);
												if (b->m_f2!=0) f->substitute(b->m_f2,b->m_u);
											} // while 

											if (b->m_f1!=0) new_selected_operator->substitute(b->m_f1,b->m_u);
											if (b->m_f2!=0) new_selected_operator->substitute(b->m_f2,b->m_u);
											if (b->m_f1!=0) new_selected_condition->substitute(b->m_f1,b->m_u);
											if (b->m_f2!=0) new_selected_condition->substitute(b->m_f2,b->m_u);
											if (b->m_f1!=0) new_selected_operator2->substitute(b->m_f1,b->m_u);
											if (b->m_f2!=0) new_selected_operator2->substitute(b->m_f2,b->m_u);

										} // while 
										delete r;	
									}

									// Add the link:
									new_plan->m_precedence_before.Add(new FeatureTerm(new_selected_operator2));
									new_plan->m_precedence_condition.Add(new FeatureTerm(new_selected_condition));
									new_plan->m_precedence_after.Add(new FeatureTerm(new_selected_operator));
								}

								// Test if the plan is valid:
								if (new_plan->check_integrity(o,domain_model)) {

#ifdef DEBUG_MESSAGES
									{
										char *s;
										printf("New plan:\n");
										s=new_plan->toStringNOOS(domain_model);
										printf("%s\n",s);
										delete []s;
										new_plan->print_orderings();
										printf("\n");
									}
#endif

									// Test if the plan is complete:
									if (new_plan->check_completeness()) {
										printf("The New plan is complete!!!!!!!!!\n\n");
										final_plan=new_plan;
									} else {
										// Add it to the list of open plans otherwise:
										open_plans.Add(new_plan);
									} // if 
								} else {
									printf("Plan had some inconsistencies!\n\n");
									delete new_plan;
								} // if
							}
						} // while 
						delete l3;
					}

				} // if 
				delete l2;

			} // while 
			delete l1;

		}

		delete plan;
	} // while 

	if (final_plan!=0) {
		char *s;
		printf("-------------------------------------------------------------\n");
		printf("Plan found (%i actions):\n",final_plan->m_operators.Length());
		s=final_plan->toStringNOOS(domain_model);
		printf("%s\n\n",s);
		delete []s;
		printf("Human readable version:\n");
		final_plan->human_readable_print(domain_model);
		printf("\n");
		delete final_plan;
	} else {
		printf("-------------------------------------------------------------\n");
		printf("No plan found\n");
	} // if 

} /* tree_planner */ 


char *Plan::toStringNOOS(FTKBase *domain_model)
{
	FeatureTerm *f,*op;
	char *s;

	f=FeatureTerm::SetFeatureTerm();
	m_operators.Rewind();
	while(m_operators.Iterate(op)) {
		f->addSetValue(new FeatureTerm(op));
	} // while 

	s=f->toStringNOOS(domain_model);
	delete f;

	return s;
} /* Plan::toStringNOOS */ 



void Plan::print_orderings(void)
{
	List<FeatureTerm> l1,l2;
	FeatureTerm *op1,*op2;

	l1.Instance(m_precedence_before);
	l2.Instance(m_precedence_after);
	l1.Rewind();
	l2.Rewind();
	while(l1.Iterate(op1) && l2.Iterate(op2)) {
		printf("%i < %i\n",m_operators.Position(op1),m_operators.Position(op2));
	} // while 
} /* Plan::print_orderings */ 


Plan *Plan::clone(FTKBase *domain_model)
{
	FeatureTerm *tmp=FeatureTerm::SetFeatureTerm(),*op,*tmp_clone;
	Plan *new_plan=new Plan();
	List<FeatureTerm> old_nodes,new_nodes;
	int pos;

	m_operators.Rewind();
	while(m_operators.Iterate(op)) tmp->addSetValue(new FeatureTerm(op));
	
	tmp_clone=tmp->clone(domain_model,&old_nodes,&new_nodes);


	m_operators.Rewind();
	while(m_operators.Iterate(op)) {
		pos=old_nodes.Position(op);
		assert(pos!=-1);
		new_plan->m_operators.Add(new FeatureTerm(new_nodes[pos]));
	} // while 
	m_precedence_before.Rewind();
	while(m_precedence_before.Iterate(op)) {
		pos=old_nodes.Position(op);
		assert(pos!=-1);
		new_plan->m_precedence_before.Add(new FeatureTerm(new_nodes[pos]));
	} // while 
	m_precedence_condition.Rewind();
	while(m_precedence_condition.Iterate(op)) {
		pos=old_nodes.Position(op);
		assert(pos!=-1);
		new_plan->m_precedence_condition.Add(new FeatureTerm(new_nodes[pos]));
	} // while 
	m_precedence_after.Rewind();
	while(m_precedence_after.Iterate(op)) {
		pos=old_nodes.Position(op);
		assert(pos!=-1);
		new_plan->m_precedence_after.Add(new FeatureTerm(new_nodes[pos]));
	} // while 

	delete tmp;
	delete tmp_clone;

	return new_plan;
} /* Plan::clone */ 


Plan *Plan::clone(FTKBase *domain_model,List<FeatureTerm> *old_nodes,List<FeatureTerm> *new_nodes)
{
	FeatureTerm *tmp=FeatureTerm::SetFeatureTerm(),*op,*tmp_clone;
	Plan *new_plan=new Plan();
	int pos;

	m_operators.Rewind();
	while(m_operators.Iterate(op)) tmp->addSetValue(new FeatureTerm(op));
	
	tmp_clone=tmp->clone(domain_model,old_nodes,new_nodes);

	m_operators.Rewind();
	while(m_operators.Iterate(op)) {
		pos=old_nodes->Position(op);
		if (pos==-1) assert("Plan not properly cloned!!!"); 
		new_plan->m_operators.Add(new FeatureTerm(new_nodes->operator [](pos)));
	} // while 
	m_precedence_before.Rewind();
	while(m_precedence_before.Iterate(op)) {
		pos=old_nodes->Position(op);
		if (pos==-1) assert("Plan not properly cloned!!!"); 
		new_plan->m_precedence_before.Add(new FeatureTerm(new_nodes->operator [](pos)));
	} // while 
	m_precedence_condition.Rewind();
	while(m_precedence_condition.Iterate(op)) {
		pos=old_nodes->Position(op);
		if (pos==-1) assert("Plan not properly cloned!!!"); 
		new_plan->m_precedence_condition.Add(new FeatureTerm(new_nodes->operator [](pos)));
	} // while 
	m_precedence_after.Rewind();
	while(m_precedence_after.Iterate(op)) {
		pos=old_nodes->Position(op);
		if (pos==-1) assert("Plan not properly cloned!!!"); 
		new_plan->m_precedence_after.Add(new FeatureTerm(new_nodes->operator [](pos)));
	} // while 

	delete tmp;
	delete tmp_clone;

	return new_plan;
} /* Plan::clone */ 


List<FeatureTerm> *Plan::get_unsatisfied_operators(void)
{
	List<FeatureTerm> *l=new List<FeatureTerm>;
	List<FeatureTerm> *l2;
	FeatureTerm *op;

	m_operators.Rewind();
	while(m_operators.Iterate(op)) {
		l2=get_unsatisfied_preconditions(op);
		if (!l2->EmptyP()) l->Add(op);
		l2->ExtractAll();
		delete l2;
	} // while 

	return l;
} /* Plan::get_unsatified_operators */ 


List<FeatureTerm> *Plan::get_operators_to_satisfy(FeatureTerm *condition,Ontology *o,FTKBase *domain_model)
{
	List<FeatureTerm> *l=new List<FeatureTerm>;
	FeatureTerm *conditions,*condition2,*op,*tmp;
	List<FeatureTerm> conditions_l;
	bool candidate;

	m_operators.Rewind();
	while(m_operators.Iterate(op)) {
		conditions=op->featureValueQuick("postconditions");
		if (conditions!=0) {
			if (conditions->isFeatureTerm()) {
				conditions_l.Add(conditions);
			} else {
				List<FeatureTerm> *l2=conditions->set_values_quick();
				l2->Rewind();
				while(l2->Iterate(condition2)) conditions_l.Add(condition2);
			} // if 
		} // if

		candidate=false;
		while(!conditions_l.EmptyP() && !candidate) {
			condition2=conditions_l.ExtractIni();
			
			tmp = simple_unification(condition,condition2,o,domain_model);
			if (tmp!=0) {
				delete tmp;
				candidate=true;
			} // if 
		} // while 

		if (candidate) l->Add(op);
	} // while 
	
	return l;
} /* Plan::get_operators_to_satisfy */ 


List<FeatureTerm> *Plan::get_unsatisfied_preconditions(FeatureTerm *op)
{
	List<FeatureTerm> *l=new List<FeatureTerm>;
	FeatureTerm *conditions,*condition;
	List<FeatureTerm> conditions_l;

	conditions=op->featureValueQuick("preconditions");
	if (conditions!=0) {
		if (conditions->isFeatureTerm()) {
			conditions_l.Add(conditions);
		} else {
			List<FeatureTerm> *l2=conditions->set_values_quick();
			l2->Rewind();
			while(l2->Iterate(condition)) conditions_l.Add(condition);
		} // if 
	} // if

	while(!conditions_l.EmptyP()) {
		condition=conditions_l.ExtractIni();
		
		if (!m_precedence_condition.MemberP(condition)) l->Add(condition);
	} // while 

	return l;
} /* Plan::get_unsatified_preconditions */ 


bool Plan::check_completeness(void)
{
	List<FeatureTerm> *l=get_unsatisfied_operators();

	if (l->EmptyP()) {
		delete l;
		return true;
	} // if 

	l->ExtractAll();
	delete l;
	return false;
} /* Plan::check_completeness */ 


bool Plan::check_integrity(Ontology *o,FTKBase *domain_model)
{
	List< List<FeatureTerm> > *l;
	List<FeatureTerm> *linear;

	printf("[ Checking integrity ]\n");

	if (restrictions_violated(o,domain_model)) return false;

	l=linear_orderings();

	printf("[ Checking integrity, %i possible linear ordering(s) ]\n",l->Length());

	while(!l->EmptyP()) {
		linear=l->ExtractIni();

		if (check_linear_integrity(linear)) {
			linear->ExtractAll();
			delete linear;

			while(!l->EmptyP()) {
				linear=l->ExtractIni();
				linear->ExtractAll();
				delete linear;
			} // while
			delete l;
			return true;
		} // if 
		linear->ExtractAll();
		delete linear;
	} // while 
	delete l;

	return false;
} /* Plan::check_integrity */ 


List<FeatureTerm> *Plan::linear_ordering(void)
{
	List< List<FeatureTerm> > *l;
	List<FeatureTerm> *linear,*linear2;

	l=linear_orderings();

	while(!l->EmptyP()) {
		linear=l->ExtractIni();

		if (check_linear_integrity(linear)) {
			while(!l->EmptyP()) {
				linear2=l->ExtractIni();
				linear2->ExtractAll();
				delete linear2;
			} // while
			delete l;
			return linear;
		} // if 

		linear->ExtractAll();
		delete linear;
	} // while 
	delete l;

	return 0;
} /* Plan::linear_ordering */ 


List< List<FeatureTerm> > *Plan::linear_orderings(void)
{
	List< List<FeatureTerm> > *orderings;
	List<FeatureTerm> *l=new List<FeatureTerm>;

	orderings=linear_orderings_internal(l);

	delete l;

	return orderings;
} /* Plan::linear_orderings */ 


List< List<FeatureTerm> > *Plan::linear_orderings_internal(List<FeatureTerm> *starting_point)
{
	List< List<FeatureTerm> > *orderings = new List< List<FeatureTerm> >,*tmp;
	List<FeatureTerm> remaining_operators,candidate_operators;
	List<FeatureTerm> l,l2,l3;
	FeatureTerm *op,*op2,*op3;
	bool candidate;

	l.Instance(m_operators);
	l.Rewind();
	while(l.Iterate(op)) {
		if (!starting_point->MemberRefP(op)) remaining_operators.Add(op);
	} // while 

	remaining_operators.Rewind();
	while(remaining_operators.Iterate(op)) {
		l2.Instance(m_precedence_before);
		l2.Rewind();
		l3.Instance(m_precedence_after);
		l3.Rewind();
		candidate=true;
		while(l2.Iterate(op2) && l3.Iterate(op3) && candidate) {
			if (*op3==*op) {
				if (remaining_operators.MemberP(op2)) candidate=false;
			} // if 
		} // while 
		if (candidate) candidate_operators.Add(op);
	} // while 

	candidate_operators.Rewind();
	while(candidate_operators.Iterate(op)) {
		List<FeatureTerm> *l=new List<FeatureTerm>;

		starting_point->Rewind();
		while(starting_point->Iterate(op2)) {
			l->Add(op2);
		} // while 
		l->Add(op);

		tmp=linear_orderings_internal(l);

		if (tmp->EmptyP()) {
			orderings->Add(l);
		} else {
			
			while(!tmp->EmptyP()) orderings->Add(tmp->ExtractIni());

			l->ExtractAll();
			delete l;
		} // if 

	} // while 

	remaining_operators.ExtractAll();
	candidate_operators.ExtractAll();
	
	return orderings;
} /* Plan::linear_orderings_internal */ 


bool Plan::check_linear_integrity(List<FeatureTerm> *linear_plan)
{
	// Check 1: That all the operators are used
	if (linear_plan->Length()!=m_operators.Length()) return false;

	// ...

	return true;
} /* Plan::check_linear_integrity */ 


void Plan::human_readable_print(FTKBase *domain_model)
{
	List<FeatureTerm> characters,places;
	FeatureTerm *c1,*c2,*c3;
	FeatureTerm *p1;
	FeatureTerm *action;
	List<FeatureTerm> *sorted_actions=linear_ordering();

	sorted_actions->Rewind();
	while(sorted_actions->Iterate(action)) {
		if (strcmp("endgame-rescue-character",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](0);
			if (!characters.MemberP(c1)) characters.Add(c1);
			c2=action->featureValueQuick("preconditions")->set_values_quick()->operator [](2);
			if (!characters.MemberP(c2)) characters.Add(c2);
			p1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](1);
			if (!places.MemberP(p1)) places.Add(p1);
			printf("The hero rescues C%i from C%i at P%i\n",characters.Position(c1),characters.Position(c2),places.Position(p1));
		} else if (strcmp("endgame-kill-character",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions");
			if (!characters.MemberP(c1)) characters.Add(c1);
			printf("The hero kills C%i\n",characters.Position(c1));
		} else if (strcmp("rescue-character",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](0);
			if (!characters.MemberP(c1)) characters.Add(c1);
			c2=action->featureValueQuick("preconditions")->set_values_quick()->operator [](2);
			if (!characters.MemberP(c2)) characters.Add(c2);
			p1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](1);
			if (!places.MemberP(p1)) places.Add(p1);
			printf("The hero rescues C%i from C%i at P%i\n",characters.Position(c1),characters.Position(c2),places.Position(p1));
		} else if (strcmp("kidnap-character",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](0);
			if (!characters.MemberP(c1)) characters.Add(c1);
			c2=action->featureValueQuick("preconditions")->set_values_quick()->operator [](2);
			if (!characters.MemberP(c2)) characters.Add(c2);
			p1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](1);
			if (!places.MemberP(p1)) places.Add(p1);
			printf("C%i is kidnapped by C%i at P%i\n",characters.Position(c1),characters.Position(c2),places.Position(p1));
		} else if (strcmp("character-is-born",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions")->set_values_quick()->operator [](0);
			if (!characters.MemberP(c1)) characters.Add(c1);
			c2=action->featureValueQuick("preconditions")->set_values_quick()->operator [](1);
			if (!characters.MemberP(c2)) characters.Add(c2);
			c3=action->featureValueQuick("postconditions");
			if (!characters.MemberP(c3)) characters.Add(c3);
			printf("C%i (%s) is born from C%i (%s) and C%i (%s) \n",characters.Position(c3),c3->getSort()->get(),
																	characters.Position(c1),c1->getSort()->get(),
																	characters.Position(c2),c2->getSort()->get());
		} else if (strcmp("character-exists",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("postconditions");
			if (!characters.MemberP(c1)) characters.Add(c1);
			printf("C%i is a %s\n",characters.Position(c1),c1->getSort()->get());
		} else if (strcmp("location-is-build",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			c1=action->featureValueQuick("preconditions");
			if (!characters.MemberP(c1)) characters.Add(c1);
			p1=action->featureValueQuick("postconditions");
			if (!places.MemberP(p1)) places.Add(p1);
			printf("C%i (%s) builds P%i (%s) \n",characters.Position(c1),c1->getSort()->get(),	
												 places.Position(p1),p1->getSort()->get());


		} else if (strcmp("not-kidnapped-to-start",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
		} else if (strcmp("endgame",
			action->featureValueQuick("name")->getSymbol()->get())==0) {
			printf("The story ends\n");
		} else {
			char *s=action->toStringNOOS(domain_model);
			printf("%s\n",s);
			delete []s;
		} // if
	} // while

	sorted_actions->ExtractAll();
	delete sorted_actions;

	characters.ExtractAll();
	places.ExtractAll();
} /* Plan::human_readable_print */ 



bool Plan::restrictions_violated(Ontology *o,FTKBase *domain_model)
{
	FeatureTerm *action,*restriction;
	FeatureTerm *restrictions;
	List<FeatureTerm> restrictions_list;

	m_operators.Rewind();
	while(m_operators.Iterate(action)) {
		restrictions=action->featureValueQuick("restrictions");
		
		if (restrictions!=0) {
			if (restrictions->isFeatureTerm()) {
				restrictions_list.Add(restrictions);
			} else {
				FeatureTerm *r;
				List<FeatureTerm> *l=restrictions->set_values_quick();
				l->Rewind();
				while(l->Iterate(r)) restrictions_list.Add(r);
			} // if 
		} // if

	} // while 

	while(!restrictions_list.EmptyP()) {
		restriction=restrictions_list.ExtractIni();

		if (restriction->getSort()==o->get_sort("different")) {
			FeatureTerm *c1,*c2;

			c1=restriction->featureValueQuick("condition1");
			c2=restriction->featureValueQuick("condition2");

			if (*c1==*c2) {
#ifdef DEBUG_MESSAGES
				printf("/* ----------------------------- *\\\n");
				printf("Different restriction violated!:\n");
				{
					char *s;
					s=c1->toStringNOOS(domain_model);
					printf("c1: %s\n",s);
					delete []s;
					s=c2->toStringNOOS(domain_model);
					printf("c2: %s\n",s);
					delete []s;
				}
				printf("\\* ----------------------------- */\n");
#endif
				restrictions_list.ExtractAll();
				return true;
			} // if
		} // if 
	} // while 

	restrictions_list.ExtractAll();
	return false;
} /* restriction_violated */ 
